home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / KERNEL / SYS.C < prev    next >
C/C++ Source or Header  |  1999-09-17  |  25KB  |  1,003 lines

  1. /*
  2.  *  linux/kernel/sys.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. #include <linux/mm.h>
  8. #include <linux/utsname.h>
  9. #include <linux/mman.h>
  10. #include <linux/smp_lock.h>
  11. #include <linux/notifier.h>
  12. #include <linux/reboot.h>
  13. #include <linux/prctl.h>
  14.  
  15. #include <asm/uaccess.h>
  16. #include <asm/io.h>
  17.  
  18. /*
  19.  * this indicates whether you can reboot with ctrl-alt-del: the default is yes
  20.  */
  21.  
  22. int C_A_D = 1;
  23.  
  24.  
  25. /*
  26.  *    Notifier list for kernel code which wants to be called
  27.  *    at shutdown. This is used to stop any idling DMA operations
  28.  *    and the like. 
  29.  */
  30.  
  31. struct notifier_block *reboot_notifier_list = NULL;
  32.  
  33. int register_reboot_notifier(struct notifier_block * nb)
  34. {
  35.     return notifier_chain_register(&reboot_notifier_list, nb);
  36. }
  37.  
  38. int unregister_reboot_notifier(struct notifier_block * nb)
  39. {
  40.     return notifier_chain_unregister(&reboot_notifier_list, nb);
  41. }
  42.  
  43.  
  44.  
  45. extern void adjust_clock(void);
  46.  
  47. asmlinkage int sys_ni_syscall(void)
  48. {
  49.     return -ENOSYS;
  50. }
  51.  
  52. static int proc_sel(struct task_struct *p, int which, int who)
  53. {
  54.     if(p->pid)
  55.     {
  56.         switch (which) {
  57.             case PRIO_PROCESS:
  58.                 if (!who && p == current)
  59.                     return 1;
  60.                 return(p->pid == who);
  61.             case PRIO_PGRP:
  62.                 if (!who)
  63.                     who = current->pgrp;
  64.                 return(p->pgrp == who);
  65.             case PRIO_USER:
  66.                 if (!who)
  67.                     who = current->uid;
  68.                 return(p->uid == who);
  69.         }
  70.     }
  71.     return 0;
  72. }
  73.  
  74. asmlinkage int sys_setpriority(int which, int who, int niceval)
  75. {
  76.     struct task_struct *p;
  77.     unsigned int priority;
  78.     int error;
  79.  
  80.     if (which > 2 || which < 0)
  81.         return -EINVAL;
  82.  
  83.     /* normalize: avoid signed division (rounding problems) */
  84.     error = ESRCH;
  85.     priority = niceval;
  86.     if (niceval < 0)
  87.         priority = -niceval;
  88.     if (priority > 20)
  89.         priority = 20;
  90.     priority = (priority * DEF_PRIORITY + 10) / 20 + DEF_PRIORITY;
  91.  
  92.     if (niceval >= 0) {
  93.         priority = 2*DEF_PRIORITY - priority;
  94.         if (!priority)
  95.             priority = 1;
  96.     }
  97.  
  98.     read_lock(&tasklist_lock);
  99.     for_each_task(p) {
  100.         if (!proc_sel(p, which, who))
  101.             continue;
  102.         if (p->uid != current->euid &&
  103.             p->uid != current->uid && !capable(CAP_SYS_NICE)) {
  104.             error = EPERM;
  105.             continue;
  106.         }
  107.         if (error == ESRCH)
  108.             error = 0;
  109.         if (priority > p->priority && !capable(CAP_SYS_NICE))
  110.             error = EACCES;
  111.         else
  112.             p->priority = priority;
  113.     }
  114.     read_unlock(&tasklist_lock);
  115.  
  116.     return -error;
  117. }
  118.  
  119. /*
  120.  * Ugh. To avoid negative return values, "getpriority()" will
  121.  * not return the normal nice-value, but a value that has been
  122.  * offset by 20 (ie it returns 0..40 instead of -20..20)
  123.  */
  124. asmlinkage int sys_getpriority(int which, int who)
  125. {
  126.     struct task_struct *p;
  127.     long max_prio = -ESRCH;
  128.  
  129.     if (which > 2 || which < 0)
  130.         return -EINVAL;
  131.  
  132.     read_lock(&tasklist_lock);
  133.     for_each_task (p) {
  134.         if (!proc_sel(p, which, who))
  135.             continue;
  136.         if (p->priority > max_prio)
  137.             max_prio = p->priority;
  138.     }
  139.     read_unlock(&tasklist_lock);
  140.  
  141.     /* scale the priority from timeslice to 0..40 */
  142.     if (max_prio > 0)
  143.         max_prio = (max_prio * 20 + DEF_PRIORITY/2) / DEF_PRIORITY;
  144.     return max_prio;
  145. }
  146.  
  147.  
  148. /*
  149.  * Reboot system call: for obvious reasons only root may call it,
  150.  * and even root needs to set up some magic numbers in the registers
  151.  * so that some mistake won't make this reboot the whole machine.
  152.  * You can also set the meaning of the ctrl-alt-del-key here.
  153.  *
  154.  * reboot doesn't sync: do that yourself before calling this.
  155.  */
  156. asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg)
  157. {
  158.     char buffer[256];
  159.  
  160.     /* We only trust the superuser with rebooting the system. */
  161.     if (!capable(CAP_SYS_BOOT))
  162.         return -EPERM;
  163.  
  164.     /* For safety, we require "magic" arguments. */
  165.     if (magic1 != LINUX_REBOOT_MAGIC1 ||
  166.         (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A &&
  167.             magic2 != LINUX_REBOOT_MAGIC2B))
  168.         return -EINVAL;
  169.  
  170.     lock_kernel();
  171.     switch (cmd) {
  172.     case LINUX_REBOOT_CMD_RESTART:
  173.         notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
  174.         printk(KERN_EMERG "Restarting system.\n");
  175.         machine_restart(NULL);
  176.         break;
  177.  
  178.     case LINUX_REBOOT_CMD_CAD_ON:
  179.         C_A_D = 1;
  180.         break;
  181.  
  182.     case LINUX_REBOOT_CMD_CAD_OFF:
  183.         C_A_D = 0;
  184.         break;
  185.  
  186.     case LINUX_REBOOT_CMD_HALT:
  187.         notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
  188.         printk(KERN_EMERG "System halted.\n");
  189.         machine_halt();
  190.         do_exit(0);
  191.         break;
  192.  
  193.     case LINUX_REBOOT_CMD_POWER_OFF:
  194.         notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
  195.         printk(KERN_EMERG "Power down.\n");
  196.         machine_power_off();
  197.         do_exit(0);
  198.         break;
  199.  
  200.     case LINUX_REBOOT_CMD_RESTART2:
  201.         if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) {
  202.             unlock_kernel();
  203.             return -EFAULT;
  204.         }
  205.         buffer[sizeof(buffer) - 1] = '\0';
  206.  
  207.         notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
  208.         printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
  209.         machine_restart(buffer);
  210.         break;
  211.  
  212.     default:
  213.         unlock_kernel();
  214.         return -EINVAL;
  215.         break;
  216.     };
  217.     unlock_kernel();
  218.     return 0;
  219. }
  220.  
  221. /*
  222.  * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
  223.  * As it's called within an interrupt, it may NOT sync: the only choice
  224.  * is whether to reboot at once, or just ignore the ctrl-alt-del.
  225.  */
  226. void ctrl_alt_del(void)
  227. {
  228.     if (C_A_D) {
  229.         notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
  230.         machine_restart(NULL);
  231.     } else
  232.         kill_proc(1, SIGINT, 1);
  233. }
  234.     
  235.  
  236. /*
  237.  * Unprivileged users may change the real gid to the effective gid
  238.  * or vice versa.  (BSD-style)
  239.  *
  240.  * If you set the real gid at all, or set the effective gid to a value not
  241.  * equal to the real gid, then the saved gid is set to the new effective gid.
  242.  *
  243.  * This makes it possible for a setgid program to completely drop its
  244.  * privileges, which is often a useful assertion to make when you are doing
  245.  * a security audit over a program.
  246.  *
  247.  * The general idea is that a program which uses just setregid() will be
  248.  * 100% compatible with BSD.  A program which uses just setgid() will be
  249.  * 100% compatible with POSIX with saved IDs. 
  250.  *
  251.  * SMP: There are not races, the GIDs are checked only by filesystem
  252.  *      operations (as far as semantic preservation is concerned).
  253.  */
  254. asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
  255. {
  256.     int old_rgid = current->gid;
  257.     int old_egid = current->egid;
  258.  
  259.     if (rgid != (gid_t) -1) {
  260.         if ((old_rgid == rgid) ||
  261.             (current->egid==rgid) ||
  262.             capable(CAP_SETGID))
  263.             current->gid = rgid;
  264.         else
  265.             return -EPERM;
  266.     }
  267.     if (egid != (gid_t) -1) {
  268.         if ((old_rgid == egid) ||
  269.             (current->egid == egid) ||
  270.             (current->sgid == egid) ||
  271.             capable(CAP_SETGID))
  272.             current->fsgid = current->egid = egid;
  273.         else {
  274.             current->gid = old_rgid;
  275.             return -EPERM;
  276.         }
  277.     }
  278.     if (rgid != (gid_t) -1 ||
  279.         (egid != (gid_t) -1 && egid != old_rgid))
  280.         current->sgid = current->egid;
  281.     current->fsgid = current->egid;
  282.     if (current->egid != old_egid)
  283.         current->dumpable = 0;
  284.     return 0;
  285. }
  286.  
  287. /*
  288.  * setgid() is implemented like SysV w/ SAVED_IDS 
  289.  *
  290.  * SMP: Same implicit races as above.
  291.  */
  292. asmlinkage int sys_setgid(gid_t gid)
  293. {
  294.     int old_egid = current->egid;
  295.  
  296.     if (capable(CAP_SETGID))
  297.         current->gid = current->egid = current->sgid = current->fsgid = gid;
  298.     else if ((gid == current->gid) || (gid == current->sgid))
  299.         current->egid = current->fsgid = gid;
  300.     else
  301.         return -EPERM;
  302.  
  303.     if (current->egid != old_egid)
  304.         current->dumpable = 0;
  305.     return 0;
  306. }
  307.   
  308. /* 
  309.  * cap_emulate_setxuid() fixes the effective / permitted capabilities of
  310.  * a process after a call to setuid, setreuid, or setresuid.
  311.  *
  312.  *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
  313.  *  {r,e,s}uid != 0, the permitted and effective capabilities are
  314.  *  cleared.
  315.  *
  316.  *  2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
  317.  *  capabilities of the process are cleared.
  318.  *
  319.  *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
  320.  *  capabilities are set to the permitted capabilities.
  321.  *
  322.  *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
  323.  *  never happen.
  324.  *
  325.  *  -astor 
  326.  */
  327. extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
  328.                        int old_suid)
  329. {
  330.     if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
  331.         (current->uid != 0 && current->euid != 0 && current->suid != 0)) {
  332.         cap_clear(current->cap_permitted);
  333.         cap_clear(current->cap_effective);
  334.     }
  335.     if (old_euid == 0 && current->euid != 0) {
  336.         cap_clear(current->cap_effective);
  337.     }
  338.     if (old_euid != 0 && current->euid == 0) {
  339.         current->cap_effective = current->cap_permitted;
  340.     }
  341. }
  342.  
  343. /*
  344.  * Unprivileged users may change the real uid to the effective uid
  345.  * or vice versa.  (BSD-style)
  346.  *
  347.  * If you set the real uid at all, or set the effective uid to a value not
  348.  * equal to the real uid, then the saved uid is set to the new effective uid.
  349.  *
  350.  * This makes it possible for a setuid program to completely drop its
  351.  * privileges, which is often a useful assertion to make when you are doing
  352.  * a security audit over a program.
  353.  *
  354.  * The general idea is that a program which uses just setreuid() will be
  355.  * 100% compatible with BSD.  A program which uses just setuid() will be
  356.  * 100% compatible with POSIX with saved IDs. 
  357.  */
  358. asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
  359. {
  360.     int old_ruid, old_euid, old_suid, new_ruid;
  361.  
  362.     new_ruid = old_ruid = current->uid;
  363.     old_euid = current->euid;
  364.     old_suid = current->suid;
  365.     if (ruid != (uid_t) -1) {
  366.         if ((old_ruid == ruid) || 
  367.             (current->euid==ruid) ||
  368.             capable(CAP_SETUID))
  369.             new_ruid = ruid;
  370.         else
  371.             return -EPERM;
  372.     }
  373.     if (euid != (uid_t) -1) {
  374.         if ((old_ruid == euid) ||
  375.             (current->euid == euid) ||
  376.             (current->suid == euid) ||
  377.             capable(CAP_SETUID))
  378.             current->fsuid = current->euid = euid;
  379.         else
  380.             return -EPERM;
  381.     }
  382.     if (ruid != (uid_t) -1 ||
  383.         (euid != (uid_t) -1 && euid != old_ruid))
  384.         current->suid = current->euid;
  385.     current->fsuid = current->euid;
  386.     if (current->euid != old_euid)
  387.         current->dumpable = 0;
  388.  
  389.     if(new_ruid != old_ruid) {
  390.         /* What if a process setreuid()'s and this brings the
  391.          * new uid over his NPROC rlimit?  We can check this now
  392.          * cheaply with the new uid cache, so if it matters
  393.          * we should be checking for it.  -DaveM
  394.          */
  395.         free_uid(current);
  396.         current->uid = new_ruid;
  397.         alloc_uid(current);
  398.     }
  399.     
  400.     if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  401.         cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  402.     }
  403.  
  404.     return 0;
  405. }
  406.  
  407.  
  408.         
  409. /*
  410.  * setuid() is implemented like SysV with SAVED_IDS 
  411.  * 
  412.  * Note that SAVED_ID's is deficient in that a setuid root program
  413.  * like sendmail, for example, cannot set its uid to be a normal 
  414.  * user and then switch back, because if you're root, setuid() sets
  415.  * the saved uid too.  If you don't like this, blame the bright people
  416.  * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
  417.  * will allow a root program to temporarily drop privileges and be able to
  418.  * regain them by swapping the real and effective uid.  
  419.  */
  420. asmlinkage int sys_setuid(uid_t uid)
  421. {
  422.     int old_euid = current->euid;
  423.     int old_ruid, old_suid, new_ruid;
  424.  
  425.     old_ruid = new_ruid = current->uid;
  426.     old_suid = current->suid;
  427.     if (capable(CAP_SETUID))
  428.         new_ruid = current->euid = current->suid = current->fsuid = uid;
  429.     else if ((uid == current->uid) || (uid == current->suid))
  430.         current->fsuid = current->euid = uid;
  431.     else
  432.         return -EPERM;
  433.  
  434.     if (current->euid != old_euid)
  435.         current->dumpable = 0;
  436.  
  437.        if (new_ruid != old_ruid) {
  438.         /* See comment above about NPROC rlimit issues... */
  439.         free_uid(current);
  440.         current->uid = new_ruid;
  441.         alloc_uid(current);
  442.     }
  443.  
  444.     if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  445.         cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  446.     }
  447.  
  448.     return 0;
  449. }
  450.  
  451.  
  452. /*
  453.  * This function implements a generic ability to update ruid, euid,
  454.  * and suid.  This allows you to implement the 4.4 compatible seteuid().
  455.  */
  456. asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
  457. {
  458.     int old_ruid = current->uid;
  459.     int old_euid = current->euid;
  460.     int old_suid = current->suid;
  461.  
  462.     if (!capable(CAP_SETUID)) {
  463.         if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
  464.             (ruid != current->euid) && (ruid != current->suid))
  465.             return -EPERM;
  466.         if ((euid != (uid_t) -1) && (euid != current->uid) &&
  467.             (euid != current->euid) && (euid != current->suid))
  468.             return -EPERM;
  469.         if ((suid != (uid_t) -1) && (suid != current->uid) &&
  470.             (suid != current->euid) && (suid != current->suid))
  471.             return -EPERM;
  472.     }
  473.     if (ruid != (uid_t) -1) {
  474.         /* See above commentary about NPROC rlimit issues here. */
  475.         free_uid(current);
  476.         current->uid = ruid;
  477.         alloc_uid(current);
  478.     }
  479.     if (euid != (uid_t) -1) {
  480.         if (euid != current->euid)
  481.             current->dumpable = 0;
  482.         current->euid = euid;
  483.         current->fsuid = euid;
  484.     }
  485.     if (suid != (uid_t) -1)
  486.         current->suid = suid;
  487.  
  488.     if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  489.         cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  490.     }
  491.  
  492.     return 0;
  493. }
  494.  
  495. asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
  496. {
  497.     int retval;
  498.  
  499.     if (!(retval = put_user(current->uid, ruid)) &&
  500.         !(retval = put_user(current->euid, euid)))
  501.         retval = put_user(current->suid, suid);
  502.  
  503.     return retval;
  504. }
  505.  
  506. /*
  507.  * Same as above, but for rgid, egid, sgid.
  508.  */
  509. asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
  510. {
  511.        if (!capable(CAP_SETGID)) {
  512.         if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
  513.             (rgid != current->egid) && (rgid != current->sgid))
  514.             return -EPERM;
  515.         if ((egid != (gid_t) -1) && (egid != current->gid) &&
  516.             (egid != current->egid) && (egid != current->sgid))
  517.             return -EPERM;
  518.         if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
  519.             (sgid != current->egid) && (sgid != current->sgid))
  520.             return -EPERM;
  521.     }
  522.     if (rgid != (gid_t) -1)
  523.         current->gid = rgid;
  524.     if (egid != (gid_t) -1) {
  525.         if (egid != current->egid)
  526.             current->dumpable = 0;
  527.         current->egid = egid;
  528.         current->fsgid = egid;
  529.     }
  530.     if (sgid != (gid_t) -1)
  531.         current->sgid = sgid;
  532.     return 0;
  533. }
  534.  
  535. asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
  536. {
  537.     int retval;
  538.  
  539.     if (!(retval = put_user(current->gid, rgid)) &&
  540.         !(retval = put_user(current->egid, egid)))
  541.         retval = put_user(current->sgid, sgid);
  542.  
  543.     return retval;
  544. }
  545.  
  546.  
  547. /*
  548.  * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
  549.  * is used for "access()" and for the NFS daemon (letting nfsd stay at
  550.  * whatever uid it wants to). It normally shadows "euid", except when
  551.  * explicitly set by setfsuid() or for access..
  552.  */
  553. asmlinkage int sys_setfsuid(uid_t uid)
  554. {
  555.     int old_fsuid;
  556.  
  557.     old_fsuid = current->fsuid;
  558.     if (uid == current->uid || uid == current->euid ||
  559.         uid == current->suid || uid == current->fsuid || 
  560.         capable(CAP_SETUID))
  561.         current->fsuid = uid;
  562.     if (current->fsuid != old_fsuid)
  563.         current->dumpable = 0;
  564.  
  565.     /* We emulate fsuid by essentially doing a scaled-down version
  566.      * of what we did in setresuid and friends. However, we only
  567.      * operate on the fs-specific bits of the process' effective
  568.      * capabilities 
  569.      *
  570.      * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
  571.      *          if not, we might be a bit too harsh here.
  572.      */
  573.     
  574.     if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  575.         if (old_fsuid == 0 && current->fsuid != 0) {
  576.             cap_t(current->cap_effective) &= ~CAP_FS_MASK;
  577.         }
  578.         if (old_fsuid != 0 && current->fsuid == 0) {
  579.             cap_t(current->cap_effective) |=
  580.                 (cap_t(current->cap_permitted) & CAP_FS_MASK);
  581.         }
  582.     }
  583.  
  584.     return old_fsuid;
  585. }
  586.  
  587. /*
  588.  * Samma pσ svenska..
  589.  */
  590. asmlinkage int sys_setfsgid(gid_t gid)
  591. {
  592.     int old_fsgid;
  593.  
  594.     old_fsgid = current->fsgid;
  595.     if (gid == current->gid || gid == current->egid ||
  596.         gid == current->sgid || gid == current->fsgid || 
  597.         capable(CAP_SETGID))
  598.         current->fsgid = gid;
  599.     if (current->fsgid != old_fsgid)
  600.         current->dumpable = 0;
  601.  
  602.     return old_fsgid;
  603. }
  604.  
  605. asmlinkage long sys_times(struct tms * tbuf)
  606. {
  607.     /*
  608.      *    In the SMP world we might just be unlucky and have one of
  609.      *    the times increment as we use it. Since the value is an
  610.      *    atomically safe type this is just fine. Conceptually its
  611.      *    as if the syscall took an instant longer to occur.
  612.      */
  613.     if (tbuf)
  614.         if (copy_to_user(tbuf, ¤t->times, sizeof(struct tms)))
  615.             return -EFAULT;
  616.     return jiffies;
  617. }
  618.  
  619. /*
  620.  * This needs some heavy checking ...
  621.  * I just haven't the stomach for it. I also don't fully
  622.  * understand sessions/pgrp etc. Let somebody who does explain it.
  623.  *
  624.  * OK, I think I have the protection semantics right.... this is really
  625.  * only important on a multi-user system anyway, to make sure one user
  626.  * can't send a signal to a process owned by another.  -TYT, 12/12/91
  627.  *
  628.  * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
  629.  * LBT 04.03.94
  630.  */
  631.  
  632. asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
  633. {
  634.     struct task_struct * p;
  635.     int err = -EINVAL;
  636.  
  637.     if (!pid)
  638.         pid = current->pid;
  639.     if (!pgid)
  640.         pgid = pid;
  641.     if (pgid < 0)
  642.         return -EINVAL;
  643.  
  644.     /* From this point forward we keep holding onto the tasklist lock
  645.      * so that our parent does not change from under us. -DaveM
  646.      */
  647.     read_lock(&tasklist_lock);
  648.  
  649.     err = -ESRCH;
  650.     p = find_task_by_pid(pid);
  651.     if (!p)
  652.         goto out;
  653.  
  654.     if (p->p_pptr == current || p->p_opptr == current) {
  655.         err = -EPERM;
  656.         if (p->session != current->session)
  657.             goto out;
  658.         err = -EACCES;
  659.         if (p->did_exec)
  660.             goto out;
  661.     } else if (p != current)
  662.         goto out;
  663.     err = -EPERM;
  664.     if (p->leader)
  665.         goto out;
  666.     if (pgid != pid) {
  667.         struct task_struct * tmp;
  668.         for_each_task (tmp) {
  669.             if (tmp->pgrp == pgid &&
  670.                 tmp->session == current->session)
  671.                 goto ok_pgid;
  672.         }
  673.         goto out;
  674.     }
  675.  
  676. ok_pgid:
  677.     p->pgrp = pgid;
  678.     err = 0;
  679. out:
  680.     /* All paths lead to here, thus we are safe. -DaveM */
  681.     read_unlock(&tasklist_lock);
  682.     return err;
  683. }
  684.  
  685. asmlinkage int sys_getpgid(pid_t pid)
  686. {
  687.     if (!pid) {
  688.         return current->pgrp;
  689.     } else {
  690.         int retval;
  691.         struct task_struct *p;
  692.  
  693.         read_lock(&tasklist_lock);
  694.         p = find_task_by_pid(pid);
  695.  
  696.         retval = -ESRCH;
  697.         if (p)
  698.             retval = p->pgrp;
  699.         read_unlock(&tasklist_lock);
  700.         return retval;
  701.     }
  702. }
  703.  
  704. asmlinkage int sys_getpgrp(void)
  705. {
  706.     /* SMP - assuming writes are word atomic this is fine */
  707.     return current->pgrp;
  708. }
  709.  
  710. asmlinkage int sys_getsid(pid_t pid)
  711. {
  712.     if (!pid) {
  713.         return current->session;
  714.     } else {
  715.         int retval;
  716.         struct task_struct *p;
  717.  
  718.         read_lock(&tasklist_lock);
  719.         p = find_task_by_pid(pid);
  720.  
  721.         retval = -ESRCH;
  722.         if(p)
  723.             retval = p->session;
  724.         read_unlock(&tasklist_lock);
  725.         return retval;
  726.     }
  727. }
  728.  
  729. asmlinkage int sys_setsid(void)
  730. {
  731.     struct task_struct * p;
  732.     int err = -EPERM;
  733.  
  734.     read_lock(&tasklist_lock);
  735.     for_each_task(p) {
  736.         if (p->pgrp == current->pid)
  737.             goto out;
  738.     }
  739.  
  740.     current->leader = 1;
  741.     current->session = current->pgrp = current->pid;
  742.     current->tty = NULL;
  743.     current->tty_old_pgrp = 0;
  744.     err = current->pgrp;
  745. out:
  746.     read_unlock(&tasklist_lock);
  747.     return err;
  748. }
  749.  
  750. /*
  751.  * Supplementary group IDs
  752.  */
  753. asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
  754. {
  755.     int i;
  756.     
  757.     /*
  758.      *    SMP: Nobody else can change our grouplist. Thus we are
  759.      *    safe.
  760.      */
  761.  
  762.     if (gidsetsize < 0)
  763.         return -EINVAL;
  764.     i = current->ngroups;
  765.     if (gidsetsize) {
  766.         if (i > gidsetsize)
  767.             return -EINVAL;
  768.         if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
  769.             return -EFAULT;
  770.     }
  771.     return i;
  772. }
  773.  
  774. /*
  775.  *    SMP: Our groups are not shared. We can copy to/from them safely
  776.  *    without another task interfering.
  777.  */
  778.  
  779. asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
  780. {
  781.     if (!capable(CAP_SETGID))
  782.         return -EPERM;
  783.     if ((unsigned) gidsetsize > NGROUPS)
  784.         return -EINVAL;
  785.     if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)))
  786.         return -EFAULT;
  787.     current->ngroups = gidsetsize;
  788.     return 0;
  789. }
  790.  
  791. int in_group_p(gid_t grp)
  792. {
  793.     if (grp != current->fsgid) {
  794.         int i = current->ngroups;
  795.         if (i) {
  796.             gid_t *groups = current->groups;
  797.             do {
  798.                 if (*groups == grp)
  799.                     goto out;
  800.                 groups++;
  801.                 i--;
  802.             } while (i);
  803.         }
  804.         return 0;
  805.     }
  806. out:
  807.     return 1;
  808. }
  809.  
  810. /*
  811.  * This should really be a blocking read-write lock
  812.  * rather than a semaphore. Anybody want to implement
  813.  * one?
  814.  */
  815. struct semaphore uts_sem = MUTEX;
  816.  
  817. asmlinkage int sys_newuname(struct new_utsname * name)
  818. {
  819.     int errno = 0;
  820.  
  821.     down(&uts_sem);
  822.     if (copy_to_user(name,&system_utsname,sizeof *name))
  823.         errno = -EFAULT;
  824.     up(&uts_sem);
  825.     return errno;
  826. }
  827.  
  828. asmlinkage int sys_sethostname(char *name, int len)
  829. {
  830.     int errno;
  831.  
  832.     if (!capable(CAP_SYS_ADMIN))
  833.         return -EPERM;
  834.     if (len < 0 || len > __NEW_UTS_LEN)
  835.         return -EINVAL;
  836.     down(&uts_sem);
  837.     errno = -EFAULT;
  838.     if (!copy_from_user(system_utsname.nodename, name, len)) {
  839.         system_utsname.nodename[len] = 0;
  840.         errno = 0;
  841.     }
  842.     up(&uts_sem);
  843.     return errno;
  844. }
  845.  
  846. asmlinkage int sys_gethostname(char *name, int len)
  847. {
  848.     int i, errno;
  849.  
  850.     if (len < 0)
  851.         return -EINVAL;
  852.     down(&uts_sem);
  853.     i = 1 + strlen(system_utsname.nodename);
  854.     if (i > len)
  855.         i = len;
  856.     errno = 0;
  857.     if (copy_to_user(name, system_utsname.nodename, i))
  858.         errno = -EFAULT;
  859.     up(&uts_sem);
  860.     return errno;
  861. }
  862.  
  863. /*
  864.  * Only setdomainname; getdomainname can be implemented by calling
  865.  * uname()
  866.  */
  867. asmlinkage int sys_setdomainname(char *name, int len)
  868. {
  869.     int errno;
  870.  
  871.     if (!capable(CAP_SYS_ADMIN))
  872.         return -EPERM;
  873.     if (len < 0 || len > __NEW_UTS_LEN)
  874.         return -EINVAL;
  875.  
  876.     down(&uts_sem);
  877.     errno = -EFAULT;
  878.     if (!copy_from_user(system_utsname.domainname, name, len)) {
  879.         errno = 0;
  880.         system_utsname.domainname[len] = 0;
  881.     }
  882.     up(&uts_sem);
  883.     return errno;
  884. }
  885.  
  886. asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
  887. {
  888.     if (resource >= RLIM_NLIMITS)
  889.         return -EINVAL;
  890.     else
  891.         return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
  892.             ? -EFAULT : 0;
  893. }
  894.  
  895. asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
  896. {
  897.     struct rlimit new_rlim, *old_rlim;
  898.  
  899.     if (resource >= RLIM_NLIMITS)
  900.         return -EINVAL;
  901.     if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
  902.         return -EFAULT;
  903.     old_rlim = current->rlim + resource;
  904.     if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
  905.          (new_rlim.rlim_max > old_rlim->rlim_max)) &&
  906.         !capable(CAP_SYS_RESOURCE))
  907.         return -EPERM;
  908.     if (resource == RLIMIT_NOFILE) {
  909.         if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
  910.             return -EPERM;
  911.     }
  912.     *old_rlim = new_rlim;
  913.     return 0;
  914. }
  915.  
  916. /*
  917.  * It would make sense to put struct rusage in the task_struct,
  918.  * except that would make the task_struct be *really big*.  After
  919.  * task_struct gets moved into malloc'ed memory, it would
  920.  * make sense to do this.  It will make moving the rest of the information
  921.  * a lot simpler!  (Which we're not doing right now because we're not
  922.  * measuring them yet).
  923.  *
  924.  * This is SMP safe.  Either we are called from sys_getrusage on ourselves
  925.  * below (we know we aren't going to exit/disappear and only we change our
  926.  * rusage counters), or we are called from wait4() on a process which is
  927.  * either stopped or zombied.  In the zombied case the task won't get
  928.  * reaped till shortly after the call to getrusage(), in both cases the
  929.  * task being examined is in a frozen state so the counters won't change.
  930.  */
  931. int getrusage(struct task_struct *p, int who, struct rusage *ru)
  932. {
  933.     struct rusage r;
  934.  
  935.     memset((char *) &r, 0, sizeof(r));
  936.     switch (who) {
  937.         case RUSAGE_SELF:
  938.             r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
  939.             r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
  940.             r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
  941.             r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
  942.             r.ru_minflt = p->min_flt;
  943.             r.ru_majflt = p->maj_flt;
  944.             r.ru_nswap = p->nswap;
  945.             break;
  946.         case RUSAGE_CHILDREN:
  947.             r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
  948.             r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
  949.             r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
  950.             r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
  951.             r.ru_minflt = p->cmin_flt;
  952.             r.ru_majflt = p->cmaj_flt;
  953.             r.ru_nswap = p->cnswap;
  954.             break;
  955.         default:
  956.             r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
  957.             r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
  958.             r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
  959.             r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
  960.             r.ru_minflt = p->min_flt + p->cmin_flt;
  961.             r.ru_majflt = p->maj_flt + p->cmaj_flt;
  962.             r.ru_nswap = p->nswap + p->cnswap;
  963.             break;
  964.     }
  965.     return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
  966. }
  967.  
  968. asmlinkage int sys_getrusage(int who, struct rusage *ru)
  969. {
  970.     if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
  971.         return -EINVAL;
  972.     return getrusage(current, who, ru);
  973. }
  974.  
  975. asmlinkage int sys_umask(int mask)
  976. {
  977.     mask = xchg(¤t->fs->umask, mask & S_IRWXUGO);
  978.     return mask;
  979. }
  980.     
  981. asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
  982.              unsigned long arg4, unsigned long arg5)
  983. {
  984.     int error = 0;
  985.     int sig;
  986.  
  987.     switch (option) {
  988.         case PR_SET_PDEATHSIG:
  989.             sig = arg2;
  990.             if (sig > _NSIG) {
  991.                 error = -EINVAL;
  992.                 break;
  993.             }
  994.             current->pdeath_signal = sig;
  995.             break;
  996.         default:
  997.             error = -EINVAL;
  998.             break;
  999.     }
  1000.     return error;
  1001. }
  1002.  
  1003.